package com.example.cloud.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.example.cloud.config.eureka.DiscoveryClientChannelFactory;
import com.example.cloud.config.interceptor.GlobalClientInterceptorConfigurerAdapter;
import com.example.cloud.config.interceptor.GlobalClientInterceptorRegistry;
import com.example.cloud.config.sleuth.MetadataInjector;
import com.example.cloud.config.sleuth.TraceClientInterceptor;

import io.grpc.LoadBalancer;
import io.grpc.util.RoundRobinLoadBalancerFactory;

/**
 * GRPC client配置
 * 
 * @author tongyufu
 *
 */
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass({ GrpcChannelFactory.class })
public class GrpcClientAutoConfiguration {

    /**
     * 客户端负载均衡
     */
    @Bean
    @ConditionalOnMissingBean
    public LoadBalancer.Factory grpcLoadBalancerFactory() {
        return RoundRobinLoadBalancerFactory.getInstance();
    }

    @Bean
    @ConditionalOnMissingBean
    public GrpcChannelFactory discoveryClientChannelFactory(DiscoveryClient discoveryClient,
                                                            LoadBalancer.Factory loadBalancerFactory,
                                                            GlobalClientInterceptorRegistry globalClientInterceptorRegistry) {
        return new DiscoveryClientChannelFactory(discoveryClient, loadBalancerFactory,
            globalClientInterceptorRegistry);
    }

    @Bean
    @ConditionalOnClass(GrpcClient.class)
    public GrpcClientBeanPostProcessor grpcClientBeanPostProcessor() {
        return new GrpcClientBeanPostProcessor();
    }

    @Bean
    public GlobalClientInterceptorRegistry globalClientInterceptorRegistry() {
        return new GlobalClientInterceptorRegistry();
    }

    @Configuration
    @ConditionalOnProperty(value = "spring.sleuth.scheduled.enabled", matchIfMissing = true)
    @ConditionalOnClass(Tracer.class)
    protected static class TraceClientAutoConfiguration {

        @Bean
        public GlobalClientInterceptorConfigurerAdapter globalTraceClientInterceptorConfigurerAdapter(final Tracer tracer) {
            return new GlobalClientInterceptorConfigurerAdapter() {

                @Override
                public void addClientInterceptors(GlobalClientInterceptorRegistry registry) {
                    registry.addClientInterceptors(
                        new TraceClientInterceptor(tracer, new MetadataInjector()));
                }
            };
        }
    }
}
